/* 
 * Copyright (c) 2012, Fromentin Xavier, Schnell Michaël, Dervin Cyrielle, Brabant Quentin
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *      * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *      * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *      * The names of its contributors may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Fromentin Xavier, Schnell Michaël, Dervin Cyrielle OR Brabant Quentin 
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package kameleon.gui.view;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.io.BufferedInputStream;
import java.io.InputStream;

import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;

import kameleon.exception.FileReadingException;
import kameleon.exception.KameleonException;
import kameleon.gui.model.FileDragAndDropHandler;
import kameleon.gui.model.Model;
import kameleon.gui.util.FileConstants;
import kameleon.gui.util.ImageUtility;
import kameleon.util.Constants;

/**
 * Main frame of the graphical interface.
 * 
 * @author		Fromentin Xavier, Schnell Michaël, Dervin Cyrielle
 * @version		1.0
 */
public class MainFrame extends JFrame 
implements FileConstants, Constants {

	/**
	 * Needed to serialize this class.
	 * 
	 * @see		java.io.Serializable
	 */
	private static final long serialVersionUID = -4479485635135930701L ;
	
	/**
	 * Name of the preferred look and feel (Nimbus).
	 */
	private static final String PREFEREED_LAF_NAME = "Nimbus" ; //$NON-NLS-1$

	/**
	 * Creates a new main frame.
	 * 
	 * @param 	debugMode
	 * 			flag indicating whether or not to print detailed error messages, 
	 * 			{@code true} activates the debug mode
	 * 
	 * @throws 	KameleonException
	 * 			If an error occurred while building the main frame
	 */
	public MainFrame(boolean debugMode) throws KameleonException {
		super(APPLICATION_NAME) ;
		this.initializeViews(debugMode) ;
		this.initializeWindow() ;
	}// MainFrame(boolean)

	/**
	 * Builds the views displayed in the main frame.
	 * 
	 * @param 	debugMode
	 * 			flag indicating whether or not to print detailed error messages, 
	 * 			{@code true} activates the debug mode
	 * 
	 * @throws 	KameleonException 
	 * 			If an error occurred while building the main frame
	 */
	protected void initializeViews(boolean debugMode) 
			throws KameleonException {
		GridBagLayout gridbag = new GridBagLayout() ;
		GridBagConstraints c ;
		this.setLayout(gridbag) ;
		Model model = new Model(debugMode) ;
		
		// Set drag and drop handler
		JComponent cp = (JComponent) this.getContentPane() ;
		cp.setTransferHandler(new FileDragAndDropHandler(model)) ;
		
		// Menu
		this.setJMenuBar(new Menu(model, this)) ;
		
		// Selected file
		c = new GridBagConstraints() ;
		c.gridwidth = 1 ;
		c.gridheight = 1 ;
		c.anchor = GridBagConstraints.NORTH ;
		c.fill = GridBagConstraints.BOTH ;
		c.gridx = 0 ;
		c.gridy = 0 ;
		c.weightx = 0.0 ;
		c.weighty = 0.0 ;
		SelectionView vueSelection = new SelectionView(this,model) ;
		vueSelection.setPreferredSize(new Dimension(350, 120)) ;
		vueSelection.setMinimumSize(  new Dimension(350, 120)) ;
		this.add(vueSelection) ;
		gridbag.setConstraints(vueSelection, c) ;

		// Currently selected file format
		c = new GridBagConstraints() ;
		c.gridwidth = 1 ;
		c.gridheight = 1 ;
		c.anchor = GridBagConstraints.NORTH ;
		c.fill = GridBagConstraints.BOTH ;
		c.gridx = 1 ;
		c.gridy = 0 ;
		c.weightx = 0.0 ;
		c.weighty = 0.0 ;
		FormatView vueFormat = new FormatView(model, this) ;
		vueFormat.setPreferredSize(new Dimension(100, 120)) ;
		vueFormat.setMinimumSize(  new Dimension(100, 120)) ;
		this.add(vueFormat) ;
		gridbag.setConstraints(vueFormat, c) ;

		// Messages
		c = new GridBagConstraints() ;
		c.gridwidth = GridBagConstraints.REMAINDER ;
		c.gridheight = 3 ;
		c.fill = GridBagConstraints.BOTH ;
		c.gridx = 2 ;
		c.gridy = 0 ;
		c.weightx = 1.0 ;
		c.weighty = 1.0 ;
		ViewMessages vm = new ViewMessages(model) ;
		this.add(vm) ;
		gridbag.setConstraints(vm, c) ;

		// Recent files
		c = new GridBagConstraints() ;
		c.gridwidth = 2 ;
		c.gridheight = 1 ;
		c.weightx = 0.0 ;
		c.weighty = 1.0 ;
		c.gridx = 0 ;
		c.gridy = 1 ;
		c.fill = GridBagConstraints.BOTH ;
		HistoryView vueHistorique = new HistoryView(model, this) ;
		vueHistorique.setPreferredSize(new Dimension(350, 380)) ;
		vueHistorique.setMinimumSize(  new Dimension(350, 380)) ;
		this.add(vueHistorique) ;
		gridbag.setConstraints(vueHistorique, c) ;

		// Output format selection
		c = new GridBagConstraints() ;
		c.gridwidth = 2 ;
		c.gridheight = 1 ;
		c.weightx = 0.0 ;
		c.weighty = 0.0 ;
		c.gridx = 0 ;
		c.gridy = 2 ;
		c.fill = GridBagConstraints.BOTH ;
		GenerationView vueGeneration = new GenerationView(model,this) ;
		vueGeneration.setPreferredSize(new Dimension(350, 200)) ;
		vueGeneration.setMinimumSize(  new Dimension(350, 200)) ;
		this.add(vueGeneration) ;
		gridbag.setConstraints(vueGeneration, c) ;

		model.notifyLanguageChange() ;
	}// initializeViews(boolean)

	/**
	 * Sets the properties (size, laf, icon, ...) of the main frame.
	 * 
	 * @throws 	FileReadingException 
	 * 			If the main frame icon could not be loaded
	 */
	protected void initializeWindow() throws FileReadingException {
		this.setPreferredSize(new Dimension(1000, 700)) ;
		this.setLookAndFeel() ;
		String icon = "/kameleon/gui/resources/%s.jpg" ; //$NON-NLS-1$
		icon = String.format(icon, "frame_icon") ; //$NON-NLS-1$
		InputStream src = new BufferedInputStream(
				MainFrame.class.getResourceAsStream(icon)) ;
		try {
			this.setIconImage((new ImageIcon(
					ImageUtility.getImageBytes(src))).getImage()) ;
			src.close() ;
		} catch (Exception ex) {
			throw new FileReadingException(
					"Unable to load main frame icon") ; //$NON-NLS-1$
		}// try
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) ;
		this.pack() ;
		this.setLocationRelativeTo(null) ;
	}// initializeWindow()

	/**
	 * Sets the look and feel of this frame to "Nimbus" if it is supported
	 * in the current environment, else keeps the default laf.
	 */
	protected void setLookAndFeel() {
		try {
			LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels() ;
			int index = 0, maxIndex = lafs.length ;
			boolean lafFound = false ;
			while ((index < maxIndex) && !lafFound) {
				LookAndFeelInfo info = lafs[index] ;
				if (PREFEREED_LAF_NAME.equals(info.getName())) {
					UIManager.setLookAndFeel(info.getClassName()) ;
					SwingUtilities.updateComponentTreeUI(this) ;
					lafFound = true ;
				}// if
				++index ;
			}// while
		} catch (Exception e) {
			/* Preferred laf not supported, fall back to using the default one. */
		}// try
	}// setLookAndFeel()

}// class MainFrame